/*
 * Copyright (C) 2014-2016 Qiujuer <qiujuer@live.cn>
 * WebSite http://www.qiujuer.net
 * Author qiujuer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.qiujuer.genius.ui.widget;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.multimodalinput.event.TouchEvent;

import net.qiujuer.genius.ui.drawable.TouchEffectDrawable;
import net.qiujuer.genius.ui.drawable.effect.Effect;
import net.qiujuer.genius.ui.drawable.effect.EffectFactory;
import net.qiujuer.genius.ui.drawable.factory.ClipFilletFactory;

public class Button extends ohos.agp.components.Button implements TouchEffectDrawable.PerformClicker,
    TouchEffectDrawable.PerformLongClicker, Component.TouchEventListener {
    /**
     * 默认圆角大小
     */
    public static final int DEFAULT_CORNER_RADIUS_VALUE = 12;
    EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
    private TouchEffectDrawable mTouchDrawable;

    /**
     * 构造函数
     *
     * @param context 上下文
     */
    public Button(Context context) {
        this(context, null);

    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrSet 自定义属性
     */
    public Button(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }


    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attr 自定义属性
     * @param styleName res资源
     */
    public Button(Context context, AttrSet attr, String styleName) {
        super(context, attr, styleName);
        init(context, attr);
    }

    //    public static final int TOUCH_EFFECT_NONE = 0;
//    public static final int TOUCH_EFFECT_AUTO = 1;
//    public static final int TOUCH_EFFECT_EASE = 2;
//    public static final int TOUCH_EFFECT_PRESS = 3;
//    public static final int TOUCH_EFFECT_RIPPLE = 4;
    private void init(Context context, AttrSet attrSet) {
        if (attrSet == null)
            return;
        int touchEffect = AttrSetUtils.get(attrSet, "gTouchEffect", EffectFactory.TOUCH_EFFECT_NONE);
        String touchColorStr = AttrSetUtils.get(attrSet, "gTouchColor", "#30000000");
        int touchColor = new Color(Color.getIntColor(touchColorStr)).getValue();
        int touchRadius = AttrSetUtils.get(attrSet, "gTouchCornerRadius", DEFAULT_CORNER_RADIUS_VALUE);
        int touchRadiusTL = AttrSetUtils.get(attrSet, "gTouchCornerRadiusTL", touchRadius);
        int touchRadiusTR = AttrSetUtils.get(attrSet, "gTouchCornerRadiusTR", touchRadius);
        int touchRadiusBL = AttrSetUtils.get(attrSet, "gTouchCornerRadiusBL", touchRadius);
        int touchRadiusBR = AttrSetUtils.get(attrSet, "gTouchCornerRadiusBR", touchRadius);
        float[] radius = new float[]{touchRadiusTL, touchRadiusTL, touchRadiusTR, touchRadiusTR,
            touchRadiusBR, touchRadiusBR, touchRadiusBL, touchRadiusBL};
        ClipFilletFactory touchFactory = new ClipFilletFactory(radius);
        float touchDurationRate = AttrSetUtils.get(attrSet, "gTouchDurationRate", 1.0f);
        int interceptEvent = AttrSetUtils.get(attrSet, "gInterceptEvent", 0x0001);
        if (touchEffect != 0) {
            TouchEffectDrawable touchEffectDrawable = new TouchEffectDrawable();
            touchEffectDrawable.setColor(touchColor);
            touchEffectDrawable.setEnterDuration(touchDurationRate);
            touchEffectDrawable.setExitDuration(touchDurationRate);
            touchEffectDrawable.setInterceptEvent(interceptEvent);
            touchEffectDrawable.setClipFactory(touchFactory);
            setTouchDrawable(touchEffectDrawable);

        }
        // Check for IDE preview render to set Font
        setEstimateSizeListener(new EstimateSizeListener() {
            @Override
            public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
                TouchEffectDrawable drawable = mTouchDrawable;
                onMeasure(widthMeasureSpec, heightMeasureSpec);
                if (drawable != null) {
                    drawable.setBounds(0, 0, getEstimatedWidth(), getEstimatedHeight());
                    mTouchDrawable.setEffect(EffectFactory.creator(touchEffect));
                }
                return false;
            }
        });

        addDrawTask(mTouchDrawable, DrawTask.BETWEEN_BACKGROUND_AND_CONTENT);
        setTouchEventListener(this);
    }

    /**
     * 宽高测量处理
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = EstimateSpec.getMode(widthMeasureSpec);
        int heightMode = EstimateSpec.getMode(heightMeasureSpec);
        int widthSize = EstimateSpec.getSize(widthMeasureSpec);
        int heightSize = EstimateSpec.getSize(heightMeasureSpec);
        int iHeight = mTouchDrawable.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom();
        int iWidth = mTouchDrawable.getIntrinsicWidth() + getPaddingLeft() + getPaddingRight();
        int measuredWidth;
        int measuredHeight;
        if (widthMode == EstimateSpec.PRECISE) {
            measuredWidth = widthSize + getPaddingLeft() + getPaddingRight();
        } else if (widthMode == EstimateSpec.NOT_EXCEED) {
            measuredWidth = Math.min(widthSize, iWidth);
        } else {
            measuredWidth = iWidth;
        }

        if (heightMode == EstimateSpec.PRECISE) {
            measuredHeight = heightSize + getPaddingTop() + getPaddingBottom();
        } else if (heightMode == EstimateSpec.NOT_EXCEED) {
            measuredHeight = Math.min(heightSize, iHeight);
        } else {
            measuredHeight = iHeight;
        }
        setEstimatedSize(EstimateSpec.getChildSizeWithMode(measuredWidth, measuredWidth, widthMode), EstimateSpec.getChildSizeWithMode(measuredHeight, measuredHeight, heightMode));
    }

    /**
     * Get the TouchEffect drawable,
     * you can set parameters in this
     *
     * @return See {@link TouchEffectDrawable}
     */
    @SuppressWarnings("unused")
    public TouchEffectDrawable getTouchDrawable() {
        return mTouchDrawable;
    }

    /**
     * In this, you can set TouchEffectDrawable,
     * to init TouchEffectDrawable.
     * <p>
     * If you not need touch effect,
     * you should set NULL.
     * <p>
     * But, if need it,
     * you should call {@link TouchEffectDrawable#setEffect(Effect)}
     *
     * @param touchDrawable TouchEffectDrawable
     */
    public void setTouchDrawable(TouchEffectDrawable touchDrawable) {
        if (mTouchDrawable != touchDrawable) {
            if (mTouchDrawable != null) {
                mTouchDrawable.setCallback(null);
            }
            mTouchDrawable = touchDrawable;
            mTouchDrawable.setMCallback(mCallback);
        }
    }

    /**
     * 实现callback接口中方法
     */
    private final TouchEffectDrawable.Callback mCallback = new TouchEffectDrawable.Callback() {
        public void invalidateComponent() {
            invalidate();
        }
    };

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        final TouchEffectDrawable d = mTouchDrawable;
        if (d != null && isEnabled()) {
            if (event.getAction() == TouchEvent.PRIMARY_POINT_UP) {
                handlerOnClick();
            }
            d.onTouch(event);
        }

        return true;
    }


    /**
     * 处理相应点击
     *
     * @return boolean boolean
     */
    public boolean handlerOnClick() {
        final TouchEffectDrawable d = mTouchDrawable;
        if (d != null) {
            return d.performClick(this);
        }
        return false;
    }


    @Override
    public boolean executeLongClick() {
        final TouchEffectDrawable d = mTouchDrawable;

        if (d != null) {
            return d.performLongClick(this) && super.executeLongClick();
        } else {
            return super.executeLongClick();
        }

    }


    @Override
    public void postPerformClick() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                handlerOnClick();
            }
        };
        handler.postTask(runnable);
    }

    @Override
    public void postPerformLongClick() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                executeLongClick();
            }
        };
        handler.postTask(runnable);
    }

}
